
/*
This file is part of jasima, the Java simulator for manufacturing and logistics.
 
Copyright 2010-2022 jasima contributors (see license.txt)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Ignore;

import jasima.core.simulation.Simulation;
import jasima.core.simulation.Simulation.ProduceResultsMessage;
import jasima.core.statistics.SummaryStat;
import jasima.core.util.ConsolePrinter;
import jasima.core.util.Util;
import jasima.shopSim.core.Job;
import jasima.shopSim.core.JobSource;
import jasima.shopSim.core.Operation;
import jasima.shopSim.core.PrioRuleTarget;
import jasima.shopSim.core.Shop;
import jasima.shopSim.core.WorkStation;
import jasima.shopSim.core.WorkStationListener;
import jasima.shopSim.util.MachineStatCollector;

/**
 * 
 * @author Torsten Hildebrandt
 */
@Ignore
public class JSExample extends Shop {
	//散列值
	final Random streamService = new Random(1234234535);
	final Random streamInterarrival = new Random(28437);
	final Random streamJobType = new Random(3424);

	//选择零件，3种零件类型，每种被选中的权值
	float probDistribJobType[] = { 0.300f, 0.800f, 1.00f };

	float meanInterarrival = 0.25f;

	private static double LENGTH_SIM = 365.0;

	//3种零件的加工时长的seed 基数？？
	float meanService[][] = { { 0.50f, 0.60f, 0.85f, 0.50f }, { 1.10f, 0.80f, 0.75f },
			{ 1.20f, 0.25f, 0.70f, 0.90f, 1.00f } };

	// Number of tasks for each job type
	WorkStation route[][];// = { { 2, 0, 1, 4 }, { 3, 0, 2 }, { 1, 4, 0, 3, 2 }
							// };

	final int NUM_JOB_TYPES = meanService.length;

	//用来统计任务在队列中的等待时长
	SummaryStat[] jobTypeDelay;

	public static AtomicInteger count = new AtomicInteger(0);

	public static void main(String args[]) throws Exception {
		Simulation s = new Simulation();

		JSExample js = new JSExample();
		s.addComponent(js);

		//总加工时长的最大时间
		s.setSimulationLength(LENGTH_SIM);

		//设置工作中心，其中的参数是工作中心的设备数   也对应了5个工序（不同零件在同一工作中心上加工也算同一种工序）
		js.addMachine(new WorkStation(3));
		js.addMachine(new WorkStation(2));
		js.addMachine(new WorkStation(4));
		js.addMachine(new WorkStation(3));
		js.addMachine(new WorkStation(1));

		// int route[][] = { { 2, 0, 1, 4 }, { 3, 0, 2 }, { 1, 4, 0, 3, 2 } };
		WorkStation[] ws = js.getMachines();
		//3种零件 ，每种零件的工序（所队对应的工作中心）
		js.route = new WorkStation[][] { { ws[2], ws[0], ws[1], ws[4] }, { ws[3], ws[0], ws[2] },
				{ ws[1], ws[4], ws[0], ws[3], ws[2] } };

		s.performRun();

		System.out.println("*************************"+count.get());

		js.report();
	} // End of main

	public JSExample() {
		super();
		setEnableLookAhead(false);
	}

	@Override
	public void init() {
		installMachineListener(new WorkStationListener() {
			@Override
			public void operationStarted(WorkStation m, PrioRuleTarget b, int oldSetupState, int newSetupState,
					double setupTime) {
				assert b.numJobsInBatch() == 1;
				Job job = b.job(0);

				Double simTime = simTime();
				Double a = simTime - job.getArriveTime();
				jobTypeDelay[job.getJobType()].value(a);
			}
		}, false);
		installMachineListener(new MachineStatCollector(), true);

		addJobSource(new JobSource() {
			@Override
			public Job createNextJob() {
				//初始化车间对象
				Job job = new Job(JSExample.this);

				//实际的来料时间？？
				Double a = simTime() + RandomHelper.expon(meanInterarrival, streamInterarrival);
				job.setRelDate(a);

				// Set JobType and TaskNumber of new job
				Integer b= RandomHelper.randomInteger(probDistribJobType, streamJobType);
				job.setJobType(b);
				// job.setJobType(1);
				//用来从 job.Operation 种获取当前工序
				job.setTaskNumber(0);

				//获取当前零件的工艺路线
				WorkStation[] ms = route[job.getJobType()];

				//设置加工工序 这里只是根据工艺路线的工序数量设置同等数量的工序数组
				Operation[] ops = Util.initializedArray(ms.length, Operation.class);
				job.setOps(ops);
				for (int i = 0; i < ms.length; i++) {
					//具体设置工序的工作中心，即指定加工工序
					job.getOps()[i].setMachine(ms[i]);
				}

				//设置工序的加工时长？？？
				for (int i = 0; i < ms.length; i++) {
					job.getOps()[i]
							.setProcTime(RandomHelper.erlang(2, meanService[job.getJobType()][i], streamService));
				}
				count.incrementAndGet();
				return job;
			}
		});

		jobTypeDelay = Util.initializedArray(NUM_JOB_TYPES, SummaryStat.class);
	}

	@Override
	public void done() {
		super.done();
	}

	public void addRecord(String s) {
		System.out.println(s);
	}

	public void report() {
		// Output begins here
		addRecord("Average total delay in queue");
		double oajtd = (double) 0.0; // Overall average job total delay
		double ajtd; // Average job total delay
		double sumProbs = (double) 0.0;
		for (int i = 0; i < NUM_JOB_TYPES; i++) {
			/*
			 * average job total delay = average delay for job type for each task times the
			 * number of tasks
			 */
			ajtd = (jobTypeDelay[i].mean() * route[i].length);
			addRecord(String.valueOf(ajtd));
			/*
			 * oajtd is a weighted average of the total time a job waits in queue. Total
			 * waits (ojtd) are multiplied by the probability job being of a particular
			 * type. Oajtd would be the typical total wait
			 */
			oajtd += (probDistribJobType[i] - sumProbs) * ajtd;
			sumProbs = probDistribJobType[i];
		}
		addRecord("Overall average job total delay: " + String.valueOf(oajtd));
		/*
		 * Compute the average number in queue, the average utilization, and the average
		 * delay in queue for each station
		 */
		addRecord("\n\nWork     Average Number     Average       Average Delay");
		addRecord("Station    in Queue        Utilization       in queue ");

		HashMap<String, Object> res = new HashMap<String, Object>();
		produceResults(res);
		ConsolePrinter.printResults(res);
		getSim().fire(new ProduceResultsMessage(res));
		ConsolePrinter.printResults(res);

		int i = 0;
		for (WorkStation m : getMachines()) {
			SummaryStat aniq = (SummaryStat) res.get(m.getName() + ".qLen");
			SummaryStat aveMachinesBusy = (SummaryStat) res.get(m.getName() + ".util");
			SummaryStat stationDelay = (SummaryStat) res.get(m.getName() + ".qWait");

			addRecord(String.valueOf(i) + "        " + String.valueOf(aniq.mean()) + "        "
					+ String.valueOf(aveMachinesBusy.mean() / m.numInGroup()) + "        "
					+ String.valueOf(stationDelay.mean()));
			i++;
		}
	}

}
